package com.cmii.sjw.department.control.jsc.service.impl;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cmii.sjw.department.control.jsc.config.OneFormConfig;
import com.cmii.sjw.department.control.jsc.mapper.*;
import com.cmii.sjw.department.control.jsc.model.*;
import com.cmii.sjw.department.control.jsc.service.MeterStorageService;
import com.cmii.sjw.department.control.jsc.service.OneFormService;
import com.cmii.sjw.department.control.jsc.util.ApiDbHelper;
import com.cmii.sjw.department.control.jsc.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.URIBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * @Author lz
 * @Date 2025-05-15 周四 08:56
 * @Version 1.0
 */
@Slf4j
@Service
public class MeterStorageServiceImpl implements MeterStorageService {

    @Autowired
    private OneFormConfig ybtConfig;
    @Autowired
    private OneFormService oneFormService;
    @Autowired
    private SaTokenDao dao;
    @Autowired
    private OrganizationInfoMapper organizationInfoMapper;
    @Autowired
    private RegionCountyMapper regionCountyMapper;
    @Autowired
    private OrganizationSchoolMapper organizationSchoolMapper;
    @Autowired
    private OrganizationMasterMapper organizationMasterMapper;
    @Autowired
    private MasterDetailMapper masterDetailMapper;
    @Autowired
    private QualificationTeacherMapper qualificationTeacherMapper;
    @Autowired
    private QualificationDetailMapper qualificationDetailMapper;
    @Autowired
    private ProfessionalCoursesMapper professionalCoursesMapper;
    @Autowired
    private QualificationAgeMapper qualificationAgeMapper;
    @Autowired
    private ProfessionalTeacherMapper professionalTeacherMapper;
    @Autowired
    private GenderDetailMapper genderDetailMapper;
    @Autowired
    private ProfessionalCountryMapper professionalCountryMapper;
    @Autowired
    private CountryDetailMapper countryDetailMapper;
    @Autowired
    private CounselorsDetailMapper counselorsDetailMapper;
    @Autowired
    private CoursesDetailMapper coursesDetailMapper;
    @Autowired
    private ProfessionalPsychologyMapper professionalPsychologyMapper;
    @Autowired
    private PsychologyDetailMapper psychologyDetailMapper;
    @Autowired
    private SchoolNumMapper schoolNumMapper;
    @Autowired
    private TeacherListMapper teacherListMapper;
    @Autowired
    private TeacherInductionMapper teacherInductionMapper;
    @Autowired
    private InductionDetailMapper inductionDetailMapper;
    @Autowired
    private TwoProfessionMapper twoProfessionMapper;
    @Autowired
    private ProfessionDetailMapper professionDetailMapper;
    @Autowired
    private ArtisticDetailMapper artisticDetailMapper;
    @Autowired
    private DoctorDetailMapper doctorDetailMapper;
    @Autowired
    private TrainingMapper trainingMapper;
    @Autowired
    private TrainingDetailMapper trainingDetailMapper;
    @Autowired
    private SchoolDetailMapper schoolDetailMapper;
    @Autowired
    private DistrictKpiMapper districtKpiMapper;

    private static final int TOKEN_EXPIRE_SECONDS = 7140;


    public String getToken() {
        String token = null;
        try {
            URIBuilder uriBuilder = new URIBuilder(ybtConfig.getUrl() + "/api/v1/auth/getToken");
            uriBuilder.addParameter("appId", ybtConfig.getAppId());
            uriBuilder.addParameter("secretKey", ybtConfig.getSecretKey());
            String url = uriBuilder.build().toString();

            String apiResult = HttpUtil.createPost(url)
                    .header(Header.CONTENT_TYPE, "application/json")
                    .execute()
                    .body();
            log.info("一表通Token ,url:{},apiResult:{}", url, apiResult);
            JSONObject content = JSON.parseObject(apiResult);

            if ("0".equals(content.getObject("code", String.class))) {
                log.info("一表通Token结果:{}", content.getString("data"));
                token = content.getJSONObject("data").get("access_token").toString();
            } else {
                log.error("一表通Token结果异常 responseCode:{}", content.getString("code"));
            }
        } catch (Exception e) {
            log.error("一表通Token请求异常 | 错误类型:{} | 详细信息:", e.getClass().getSimpleName(), e);
        }
        return token;
    }

    @Override
    public String TokenManager() {
        String token = dao.get("one-form:token");
        if (StringUtils.isEmpty(token)) {
            synchronized (this) {
                token = dao.get("one-form:token"); // 双重检查
                if (StringUtils.isEmpty(token)) {
                    try {
                        token = getToken();
                        log.info("获取新的一表通Token:{}", token);
                        dao.set("one-form:token", token, TOKEN_EXPIRE_SECONDS);
                    } catch (Exception e) {
                        log.error("生成Token失败", e);
                        throw new RuntimeException("Token生成异常"); // 根据业务需求处理异常
                    }
                }
            }
        }
        return token;
    }

    @Override
    public Result saveHigh(String year) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/highList";
        String url = baseUrl + endpoint;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return Result.error("获取 Token 失败");
            }

            String response = HttpUtil.createPost(url)
                    .header(Header.AUTHORIZATION, token)
                    .form(Map.of("year", year))
                    .execute()
                    .body();

            log.info("请求高校列表响应: {}", response);
            JSONObject result = JSON.parseObject(response);

            if (!"0".equals(result.getString("code")) && !"200".equals(result.getString("code"))) {
                return Result.error("接口返回失败: " + result.getString("message"));
            }

            JSONArray data = result.getJSONArray("data");
            if (data == null || data.isEmpty()) {
                return Result.error("返回数据为空");
            }

            for (int i = 0; i < data.size(); i++) {
                JSONObject item = data.getJSONObject(i);

                String orgNo = item.getString("orgnazitionNo");
                String orgName = item.getString("orgnazitionName");

                if (StringUtils.isEmpty(orgNo) || StringUtils.isEmpty(orgName)) {
                    log.warn("跳过非法高校数据 orgnazitionNo={}, orgnazitionName={}", orgNo, orgName);
                    continue;
                }

                OrganizationInfo info = new OrganizationInfo();
                info.setOrgnazitionNo(orgNo);
                info.setOrgnazitionName(orgName);
                info.setGatherOrganizationName(item.getString("gatherOrganizationName"));
                info.setSchoolRunningTypeNo(item.getString("schoolRunningTypeNo"));
                info.setSchoolRunningType(item.getString("schoolRunningType"));
                info.setGatherOrganizationNo(item.getString("gatherOrganizationNo"));
                info.setCreateTime(LocalDateTime.now());
                info.setUpdateTime(LocalDateTime.now());
                info.setIsDeleted(0);

                // 查重
                LambdaQueryWrapper<OrganizationInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(OrganizationInfo::getOrgnazitionNo, orgNo);
                OrganizationInfo existing = organizationInfoMapper.selectOne(wrapper);

                if (existing != null) {
                    info.setId(existing.getId());
                    int updated = organizationInfoMapper.updateById(info);
                    log.info("更新高校记录: {}，结果: {}", info, updated);
                } else {
                    int inserted = organizationInfoMapper.insert(info);
                    log.info("插入高校记录: {}，结果: {}", info, inserted);
                }
            }

            return Result.success();

        } catch (Exception e) {
            log.error("请求高校列表异常: {}", e.getMessage(), e);
            return Result.error("请求高校列表异常");
        }
    }

    /**
     * 区县列表入库
     *
     * @param year 年份
     * @return
     */

    @Override
    public Result saveCounty(String year) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/countyList";
        String url = baseUrl + endpoint;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return Result.error("获取 Token 失败");
            }

            String response = HttpUtil.createPost(url)
                    .header(Header.AUTHORIZATION, token)
                    .form(Map.of("year", year))
                    .execute()
                    .body();

            log.info("请求区县列表响应: {}", response);
            JSONObject result = JSON.parseObject(response);

            if (!"0".equals(result.getString("code")) && !"200".equals(result.getString("code"))) {
                return Result.error("接口返回失败: " + result.getString("message"));
            }

            JSONArray data = result.getJSONArray("data");
            if (data == null || data.isEmpty()) {
                return Result.error("返回数据为空");
            }

            for (int i = 0; i < data.size(); i++) {
                JSONObject item = data.getJSONObject(i);
                String countyNo = item.getString("countyNo");
                String countyName = item.getString("countyName");

                if (StringUtils.isEmpty(countyNo) || StringUtils.isEmpty(countyName)) {
                    log.warn("跳过非法数据 countyNo={}, countyName={}", countyNo, countyName);
                    continue;
                }

                RegionCounty region = new RegionCounty();
                region.setCountyNo(countyNo);
                region.setCountyName(countyName);
                region.setCreateTime(LocalDateTime.now());
                region.setUpdateTime(LocalDateTime.now());
                region.setIsDeleted(0);

                // 先查是否存在
                RegionCounty existing = regionCountyMapper.selectByCountyNo(countyNo);
                if (existing != null) {
                    region.setId(existing.getId());
                    int updated = regionCountyMapper.updateByPrimaryKey(region);
                    log.info("更新区县记录: {}，结果: {}", region, updated);
                } else {
                    int inserted = regionCountyMapper.insert(region);
                    log.info("插入区县记录: {}，结果: {}", region, inserted);
                }
            }

            return Result.success();

        } catch (Exception e) {
            log.error("请求区县列表异常: {}", e.getMessage(), e);
            return Result.error("请求区县列表异常");
        }
    }

    /**
     * 学校列表入库
     *
     * @param year       年份
     * @param schoolType 学校类型
     * @param county     区县
     * @return
     */
    @Override
    public Result saveSchool(String year, String schoolType, String county) {
        // 启动异步任务
        CompletableFuture.runAsync(() -> saveSchoolData(year, schoolType, county));
        return Result.success("学校列表数据入库");
    }

    @Async
    public void saveSchoolData(String year, String schoolType, String county) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/schoolList";
        String url = baseUrl + endpoint;

        int pageNum = 1;
        int pageSize = 100;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return;
            }

            while (true) {
                Map<String, Object> params = new HashMap<>();
                params.put("year", year);
                params.put("schoolType", schoolType);
                params.put("search", "");
                params.put("county", county);
                params.put("pageNum", pageNum);
                params.put("pageSize", pageSize);

                String response = HttpUtil.createPost(url)
                        .header(Header.AUTHORIZATION, token)
                        .form(params)
                        .execute()
                        .body();

                JSONObject result = JSON.parseObject(response);
                if (!"0".equals(result.getString("code")) && !"200".equals(result.getString("code"))) {
                    log.error("接口返回失败: {}", result.getString("message"));
                    return;
                }

                JSONObject data = result.getJSONObject("data");
                JSONArray list = data.getJSONArray("list");
                if (list == null || list.isEmpty()) {
                    break;
                }

                for (int i = 0; i < list.size(); i++) {
                    JSONObject item = list.getJSONObject(i);
                    String orgNo = item.getString("orgnazitionNo");
                    String orgName = item.getString("orgnazitionName");

                    if (StringUtils.isEmpty(orgNo) || StringUtils.isEmpty(orgName)) {
                        log.warn("跳过非法数据 orgNo={}, orgName={}", orgNo, orgName);
                        continue;
                    }

                    OrganizationSchool info = new OrganizationSchool();
                    info.setOrgnazitionNo(orgNo);
                    info.setOrgnazitionName(orgName);
                    info.setGatherOrganizationName(item.getString("gatherOrganizationName"));
                    info.setSchoolRunningTypeNo(item.getString("schoolRunningTypeNo"));
                    info.setSchoolRunningType(item.getString("schoolRunningType"));
                    info.setGatherOrganizationNo(item.getString("gatherOrganizationNo"));
                    info.setCreateTime(LocalDateTime.now());
                    info.setUpdateTime(LocalDateTime.now());
                    info.setIsDeleted(0);

                    // 查询是否已存在
                    LambdaQueryWrapper<OrganizationSchool> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(OrganizationSchool::getOrgnazitionNo, orgNo);
                    OrganizationSchool existing = organizationSchoolMapper.selectOne(wrapper);

                    if (existing != null) {
                        info.setId(existing.getId());
                        organizationSchoolMapper.updateById(info);
                        log.info("更新学校记录: {}", info);
                    } else {
                        organizationSchoolMapper.insert(info);
                        log.info("新增学校记录: {}", info);
                    }
                }

                // 分页判断是否结束
                int totalPages = data.getIntValue("pages");
                if (pageNum >= totalPages) break;
                pageNum++;
            }

            log.info("学校数据保存完成");

        } catch (Exception e) {
            log.error("请求学校列表异常: {}", e.getMessage(), e);
        }
    }

    @Override
    public Result saveMaster(String year) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/masterData";
        String url = baseUrl + endpoint;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return Result.error("获取 Token 失败");
            }

            // --------- 处理 “全市” 数据 ------------
            String cityResponse = HttpUtil.createPost(url)
                    .header(Header.AUTHORIZATION, token)
                    .form(Map.of("year", year))
                    .execute()
                    .body();

            log.info("请求全市教师数据响应: {}", cityResponse);
            JSONObject cityResult = JSON.parseObject(cityResponse);

            if (!"0".equals(cityResult.getString("code")) && !"200".equals(cityResult.getString("code"))) {
                return Result.error("接口返回失败: " + cityResult.getString("message"));
            }

            JSONArray cityData = cityResult.getJSONArray("data");
            if (cityData != null && !cityData.isEmpty()) {
                for (int i = 0; i < cityData.size(); i++) {
                    JSONObject item = cityData.getJSONObject(i);
                    String name = item.getString("name");
                    Integer num = item.getInteger("num");

                    if (StringUtils.isEmpty(name)) {
                        log.warn("跳过非法教师数据 name=null");
                        continue;
                    }

                    OrganizationMaster record = new OrganizationMaster();
                    record.setName(name);
                    record.setNum(num);
                    record.setGatherOrganizationName("全市");
                    record.setUpdateTime(LocalDateTime.now());
                    record.setIsDeleted(0);

                    // 查重
                    LambdaQueryWrapper<OrganizationMaster> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(OrganizationMaster::getName, name)
                            .eq(OrganizationMaster::getGatherOrganizationName, "全市");

                    OrganizationMaster existing = organizationMasterMapper.selectOne(wrapper);
                    if (existing != null) {
                        record.setId(existing.getId());
                        int updated = organizationMasterMapper.updateById(record);
                        log.info("更新全市教师数据: {}，结果: {}", record, updated);
                    } else {
                        record.setCreateTime(LocalDateTime.now());
                        int inserted = organizationMasterMapper.insert(record);
                        log.info("插入全市教师数据: {}，结果: {}", record, inserted);
                    }
                }
            }

            // --------- 处理各区县数据 ------------
            Result countyResult = oneFormService.countyList(year);
            if (countyResult == null || countyResult.getData() == null) {
                return Result.error("获取区县列表失败");
            }

            List<Map<String, Object>> countyList = (List<Map<String, Object>>) countyResult.getData();
            for (Map<String, Object> countyItem : countyList) {
                String county = (String) countyItem.get("countyName");
                if (StringUtils.isEmpty(county)) continue;

                String countyResponse = HttpUtil.createPost(url)
                        .header(Header.AUTHORIZATION, token)
                        .form(Map.of("year", year, "county", county))
                        .execute()
                        .body();

                log.info("请求区县 [{}] 教师数据响应: {}", county, countyResponse);
                JSONObject countyResultObj = JSON.parseObject(countyResponse);

                if (!"0".equals(countyResultObj.getString("code")) && !"200".equals(countyResultObj.getString("code"))) {
                    log.warn("接口返回失败: {} - {}", county, countyResultObj.getString("message"));
                    continue;
                }

                JSONArray data = countyResultObj.getJSONArray("data");
                if (data == null || data.isEmpty()) continue;

                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    String name = item.getString("name");
                    Integer num = item.getInteger("num");

                    if (StringUtils.isEmpty(name)) continue;

                    OrganizationMaster record = new OrganizationMaster();
                    record.setName(name);
                    record.setNum(num);
                    record.setGatherOrganizationName(county);
                    record.setUpdateTime(LocalDateTime.now());
                    record.setIsDeleted(0);

                    // 查重
                    LambdaQueryWrapper<OrganizationMaster> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(OrganizationMaster::getName, name)
                            .eq(OrganizationMaster::getGatherOrganizationName, county);

                    OrganizationMaster existing = organizationMasterMapper.selectOne(wrapper);
                    if (existing != null) {
                        record.setId(existing.getId());
                        int updated = organizationMasterMapper.updateById(record);
                        log.info("更新区县教师数据: {}，结果: {}", record, updated);
                    } else {
                        record.setCreateTime(LocalDateTime.now());
                        int inserted = organizationMasterMapper.insert(record);
                        log.info("插入区县教师数据: {}，结果: {}", record, inserted);
                    }
                }
            }

            return Result.success();

        } catch (Exception e) {
            log.error("请求教师数量数据异常: {}", e.getMessage(), e);
            return Result.error("请求教师数量数据异常");
        }
    }


    @Override
    public Result saveMasterDetail(String year) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/masterDetail";
        String url = baseUrl + endpoint;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return Result.error("获取 Token 失败");
            }

            int countCollege = 0;
            int countCounty = 0;
            LocalDateTime now = LocalDateTime.now();

            // --- 调用高校数据 type=2 ---
            String responseCollege = HttpUtil.createPost(url)
                    .header(Header.AUTHORIZATION, token)
                    .form(Map.of("year", year, "type", "2"))
                    .execute()
                    .body();
            log.info("高校数据响应: {}", responseCollege);
            JSONObject resultCollege = JSON.parseObject(responseCollege);

            if (!"0".equals(resultCollege.getString("code")) && !"200".equals(resultCollege.getString("code"))) {
                return Result.error("高校接口返回失败: " + resultCollege.getString("message"));
            }

            JSONArray collegeData = resultCollege.getJSONArray("data");
            if (collegeData != null && !collegeData.isEmpty()) {
                for (int i = 0; i < collegeData.size(); i++) {
                    JSONObject item = collegeData.getJSONObject(i);
                    String orgName = item.getString("organizationName");
                    Integer num = item.getInteger("num");

                    if (orgName == null || num == null) {
                        log.warn("跳过非法高校数据 organizationName={}, num={}", orgName, num);
                        continue;
                    }

                    MasterDetail info = new MasterDetail();
                    info.setOrganizationName(orgName);
                    info.setNum(num);
                    info.setCreateTime(now);
                    info.setUpdateTime(now);
                    info.setIsDeleted(0);

                    LambdaQueryWrapper<MasterDetail> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(MasterDetail::getOrganizationName, orgName);
                    MasterDetail existing = masterDetailMapper.selectOne(wrapper);

                    if (existing != null) {
                        info.setId(existing.getId());
                        int updated = masterDetailMapper.updateById(info);
                        log.info("更新高校记录: {}，结果: {}", info, updated);
                    } else {
                        int inserted = masterDetailMapper.insert(info);
                        log.info("插入高校记录: {}，结果: {}", info, inserted);
                    }

                    countCollege++;
                }
            }

            // --- 调用区县数据 type=1 ---
            String responseCounty = HttpUtil.createPost(url)
                    .header(Header.AUTHORIZATION, token)
                    .form(Map.of("year", year, "type", "1"))
                    .execute()
                    .body();
            log.info("区县数据响应: {}", responseCounty);
            JSONObject resultCounty = JSON.parseObject(responseCounty);

            if (!"0".equals(resultCounty.getString("code")) && !"200".equals(resultCounty.getString("code"))) {
                return Result.error("区县接口返回失败: " + resultCounty.getString("message"));
            }

            JSONArray countyData = resultCounty.getJSONArray("data");
            if (countyData != null && !countyData.isEmpty()) {
                for (int i = 0; i < countyData.size(); i++) {
                    JSONObject item = countyData.getJSONObject(i);

                    String countyName = item.getString("countyName");
                    String countyNo = item.getString("countyNo");
                    Integer kindergarten = item.getInteger("kindergarten");
                    Integer smallSchool = item.getInteger("primary");
                    Integer junior = item.getInteger("junior");
                    Integer senior = item.getInteger("senior");
                    Integer vocational = item.getInteger("vocational");


                    MasterDetail info = new MasterDetail();
                    info.setCountyName(countyName);
                    info.setCountyNo(countyNo);
                    info.setKindergarten(kindergarten != null ? kindergarten.toString() : null);
                    info.setSmallSchool(smallSchool != null ? smallSchool.toString() : null);
                    info.setJunior(junior != null ? junior.toString() : null);
                    info.setSenior(senior != null ? senior.toString() : null);
                    info.setVocational(vocational != null ? vocational.toString() : null);
                    info.setCreateTime(now);
                    info.setUpdateTime(now);
                    info.setIsDeleted(0);

                    LambdaQueryWrapper<MasterDetail> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(MasterDetail::getCountyNo, countyNo);
                    MasterDetail existing = masterDetailMapper.selectOne(wrapper);

                    if (existing != null) {
                        info.setId(existing.getId());
                        int updated = masterDetailMapper.updateById(info);
                        log.info("更新区县记录: {}，结果: {}", info, updated);
                    } else {
                        int inserted = masterDetailMapper.insert(info);
                        log.info("插入区县记录: {}，结果: {}", info, inserted);
                    }

                    countCounty++;
                }
            }

            log.info("高校记录处理完成，共 {} 条", countCollege);
            log.info("区县记录处理完成，共 {} 条", countCounty);
            return Result.success();

        } catch (Exception e) {
            log.error("请求专任教师数量详情异常: {}", e.getMessage(), e);
            return Result.error("请求专任教师数量详情异常");
        }
    }

    @Override
    public Result saveQualification(String year) {
        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/qualification";
        String url = baseUrl + endpoint;

        try {
            String token = TokenManager();
            if (token == null) {
                log.error("TokenManager 返回 null");
                return Result.error("获取 Token 失败");
            }

            int totalCount = 0;
            LocalDateTime now = LocalDateTime.now();

            // ----- 处理区县数据 -----
            Result countyListResult = oneFormService.countyList(year);
            if (countyListResult == null ||
                    (!"0".equals(Objects.toString(countyListResult.getCode())) &&
                            !"200".equals(Objects.toString(countyListResult.getCode())))) {
                return Result.error("获取区县列表失败: " + (countyListResult != null ? countyListResult.getMessage() : "返回为空"));
            }

            List<Map<String, Object>> countyList = (List<Map<String, Object>>) countyListResult.getData();
            if (countyList == null) countyList = new ArrayList<>();
            Map<String, Object> summaryCounty = new HashMap<>();
            summaryCounty.put("countyName", "汇总");
            countyList.add(0, summaryCounty);

            String[] typeList = {"汇总", "幼儿园", "小学", "初中", "高中", "中职", "高校"};

            for (Map<String, Object> county : countyList) {
                String countyName = Objects.toString(county.get("countyName"), null);
                for (String type : typeList) {
                    String realCountyParam = "汇总".equals(countyName) ? "" : countyName;
                    String response = HttpUtil.createPost(url)
                            .header(Header.AUTHORIZATION, token)
                            .form(Map.of("year", year, "county", realCountyParam, "type", type))
                            .execute()
                            .body();

                    log.info("学历情况响应 [县:{} 类型:{}]: {}", countyName, type, response);
                    JSONObject result = JSON.parseObject(response);
                    if (!"0".equals(result.getString("code")) && !"200".equals(result.getString("code"))) continue;
                    JSONArray dataList = result.getJSONArray("data");
                    if (dataList == null || dataList.isEmpty()) continue;

                    for (int i = 0; i < dataList.size(); i++) {
                        JSONObject item = dataList.getJSONObject(i);
                        String name = item.getString("name");
                        Integer num = item.getInteger("num");
                        String percentage = item.getString("percentage");
                        if (name == null || num == null) continue;

                        QualificationTeacher info = new QualificationTeacher();
                        info.setCountyName(countyName);
                        info.setType(type);
                        info.setName(name);
                        info.setNum(num);
                        info.setPercentage(percentage);
                        info.setCreateTime(now);
                        info.setUpdateTime(now);
                        info.setIsDeleted(0);

                        LambdaQueryWrapper<QualificationTeacher> wrapper = new LambdaQueryWrapper<>();
                        wrapper.eq(QualificationTeacher::getCountyName, countyName)
                                .eq(QualificationTeacher::getType, type)
                                .eq(QualificationTeacher::getName, name);

                        QualificationTeacher existing = qualificationTeacherMapper.selectOne(wrapper);
                        if (existing != null) {
                            info.setId(existing.getId());
                            qualificationTeacherMapper.updateById(info);
                        } else {
                            qualificationTeacherMapper.insert(info);
                        }
                        totalCount++;
                    }
                }
            }

            // ----- 处理高校数据 -----
            Result collegeListResult = oneFormService.highList(year);
            if (collegeListResult == null ||
                    (!"0".equals(Objects.toString(collegeListResult.getCode())) &&
                            !"200".equals(Objects.toString(collegeListResult.getCode())))) {
                return Result.error("获取高校列表失败: " + (collegeListResult != null ? collegeListResult.getMessage() : "返回为空"));
            }

            List<Map<String, Object>> collegeList = (List<Map<String, Object>>) collegeListResult.getData();
            if (collegeList == null) {
                collegeList = new ArrayList<>();
            }

            for (Map<String, Object> college : collegeList) {
                String organizationName = Objects.toString(college.get("orgnazitionName"), null);
                if (organizationName == null) continue;

                String response = HttpUtil.createPost(url)
                        .header(Header.AUTHORIZATION, token)
                        .form(Map.of("year", year, "county", organizationName, "type", "高校"))
                        .execute()
                        .body();

                log.info("高校学历响应 [{}]: {}", organizationName, response);
                JSONObject result = JSON.parseObject(response);

                if (!"0".equals(result.getString("code")) && !"200".equals(result.getString("code"))) {
                    log.warn("高校学历接口失败 [{}]: {}", organizationName, result.getString("message"));
                    continue;
                }

                JSONArray dataList = result.getJSONArray("data");
                if (dataList == null || dataList.isEmpty()) continue;

                for (int i = 0; i < dataList.size(); i++) {
                    JSONObject item = dataList.getJSONObject(i);
                    Integer num = item.getInteger("num");
                    String percentage = item.getString("percentage");
                    String name = item.getString("name");

                    if (name == null || num == null) continue;

                    QualificationTeacher info = new QualificationTeacher();
                    info.setCountyName(null);
                    info.setSchoolName(organizationName);
                    info.setType("高校");
                    info.setName(name);
                    info.setNum(num);
                    info.setPercentage(percentage);
                    info.setCreateTime(now);
                    info.setUpdateTime(now);
                    info.setIsDeleted(0);

                    LambdaQueryWrapper<QualificationTeacher> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(QualificationTeacher::getSchoolName, organizationName)
                            .eq(QualificationTeacher::getType, "高校")
                            .eq(QualificationTeacher::getName, name);

                    QualificationTeacher existing = qualificationTeacherMapper.selectOne(wrapper);
                    if (existing != null) {
                        info.setId(existing.getId());
                        qualificationTeacherMapper.updateById(info);
                    } else {
                        qualificationTeacherMapper.insert(info);
                    }
                    totalCount++;
                }
            }
            log.info("学历情况处理完成，共 {} 条记录", totalCount);
            return Result.success("学历情况保存完成，共 " + totalCount + " 条记录");
        } catch (Exception e) {
            log.error("保存学历情况数据异常: {}", e.getMessage(), e);
            return Result.error("保存学历情况数据异常");
        }
    }

    @Override
    public Result saveQualificationDetail(String year) {

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        // 先拿区县列表
        Result countyListResult = oneFormService.countyList(year);
        if (countyListResult == null ||
                (!"0".equals(Objects.toString(countyListResult.getCode())) &&
                        !"200".equals(Objects.toString(countyListResult.getCode())))) {
            return Result.error("获取区县列表失败: " + (countyListResult != null ? countyListResult.getMessage() : "返回为空"));
        }

        List<Map<String, Object>> countyList = (List<Map<String, Object>>) countyListResult.getData();
        if (countyList == null) countyList = new ArrayList<>();

        Map<String, Object> summaryCounty = new HashMap<>();
        summaryCounty.put("countyName", "汇总");
        countyList.add(0, summaryCounty);

        if (countyList.isEmpty()) return Result.error("区县列表为空（含汇总）");

        String[] schoolTypes = {"幼儿园", "小学", "初中", "高中", "中职", "高校"};
        int totalCount = 0;
        LocalDateTime now = LocalDateTime.now();

        // --- 处理区县数据，type=1 表示区县 ---
        for (Map<String, Object> county : countyList) {
            String countyName = Objects.toString(county.get("countyName"), null);
            for (String schoolType : schoolTypes) {
                String realCountyParam = "汇总".equals(countyName) ? "" : countyName;

                log.info("请求区县学历详情参数：year={}, county={}, type=1, schoolType={}", year, realCountyParam, schoolType);

                JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/qualificationDetail", Map.of(
                        "year", year,
                        "county", realCountyParam,
                        "type", "1",
                        "schoolType", schoolType
                ));

                JSONArray dataList = result.getJSONArray("data");
                if (dataList == null || dataList.isEmpty()) {
                    log.info("区县 {} 学校类型 {} 返回数据为空，跳过", countyName, schoolType);
                    continue;
                }

                for (int i = 0; i < dataList.size(); i++) {
                    JSONObject item = dataList.getJSONObject(i);
                    Integer num = item.getInteger("num");
                    String percentage = item.getString("percentage");
                    String name = item.getString("name");

                    if (StrUtil.isBlank(name) || num == null) {
                        log.warn("跳过非法学历数据: name={}, num={}", name, num);
                        continue;
                    }

                    QualificationDetail detail = new QualificationDetail();
                    detail.setCountyName(countyName);
                    detail.setSchoolName(null);
                    detail.setType("1");
                    detail.setSchoolType(schoolType);
                    detail.setName(name);
                    detail.setNum(num);
                    detail.setPercentage(percentage);
                    detail.setCreateTime(now);
                    detail.setUpdateTime(now);
                    detail.setIsDeleted(0);

                    ApiDbHelper.insertOrUpdate(qualificationDetailMapper, detail, (LambdaQueryWrapper<QualificationDetail> wrapper) ->
                            wrapper.eq(QualificationDetail::getCountyName, countyName)
                                    .eq(QualificationDetail::getType, "1")
                                    .eq(QualificationDetail::getSchoolType, schoolType)
                                    .eq(QualificationDetail::getName, name)
                    );

                    totalCount++;
                }
            }
        }

        // --- 处理高校数据，type=2 表示高校 ---
        Result collegeListResult = oneFormService.highList(year);
        if (collegeListResult == null ||
                (!"0".equals(Objects.toString(collegeListResult.getCode())) &&
                        !"200".equals(Objects.toString(collegeListResult.getCode())))) {
            return Result.error("获取高校列表失败: " + (collegeListResult != null ? collegeListResult.getMessage() : "返回为空"));
        }

        List<Map<String, Object>> collegeList = (List<Map<String, Object>>) collegeListResult.getData();
        if (collegeList == null) collegeList = new ArrayList<>();

        for (Map<String, Object> college : collegeList) {

            String schoolName = Objects.toString(college.get("orgnazitionName"), null);
            if (StrUtil.isBlank(schoolName)) {
                log.warn("高校名称为空，跳过");
                continue;
            }

            for (String schoolType : schoolTypes) {
                log.info("请求高校学历详情参数：year={}, organization={}, type=2, schoolType={}", year, schoolName, schoolType);

                JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/qualificationDetail", Map.of(
                        "year", year,
                        "organization", schoolName,
                        "type", "2",
                        "schoolType", schoolType
                ));

                JSONArray dataList = result.getJSONArray("data");
                if (dataList == null || dataList.isEmpty()) {
                    log.info("高校 {} 学校类型 {} 返回数据为空，跳过", schoolName, schoolType);
                    continue;
                }

                for (int i = 0; i < dataList.size(); i++) {
                    JSONObject item = dataList.getJSONObject(i);
                    Integer num = item.getInteger("num");
                    String percentage = item.getString("percentage");
                    String name = item.getString("name");

                    if (StrUtil.isBlank(name) || num == null) {
                        log.warn("跳过非法学历数据: name={}, num={}", name, num);
                        continue;
                    }

                    QualificationDetail detail = new QualificationDetail();
                    detail.setCountyName(null);
                    detail.setSchoolName(schoolName);
                    detail.setType("2");
                    detail.setSchoolType(schoolType);
                    detail.setName(name);
                    detail.setNum(num);
                    detail.setPercentage(percentage);
                    detail.setCreateTime(now);
                    detail.setUpdateTime(now);
                    detail.setIsDeleted(0);

                    ApiDbHelper.insertOrUpdate(qualificationDetailMapper, detail, (LambdaQueryWrapper<QualificationDetail> wrapper) ->
                            wrapper.eq(QualificationDetail::getSchoolName, schoolName)
                                    .eq(QualificationDetail::getType, "2")
                                    .eq(QualificationDetail::getSchoolType, schoolType)
                                    .eq(QualificationDetail::getName, name)
                    );

                    totalCount++;
                }
            }
        }

        log.info("学历情况详情处理完成，共 {} 条记录", totalCount);
        return Result.success("学历情况详情保存完成，共 " + totalCount + " 条记录");
    }

    @Override
    public Result saveQualificationAge(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int totalCount = 0;

        // type = 1（区县） 和 2（高校）
        for (int t = 1; t <= 2; t++) {
            String type = String.valueOf(t);
            JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/age", Map.of(
                    "year", year,
                    "type", type
            ));

            JSONArray dataList = result.getJSONArray("data");
            if (dataList == null || dataList.isEmpty()) continue;

            for (int i = 0; i < dataList.size(); i++) {
                JSONObject item = dataList.getJSONObject(i);
                String name = item.getString("name");
                JSONArray values = item.getJSONArray("value");
                if (values == null) continue;

                for (int j = 0; j < values.size(); j++) {
                    JSONObject ageItem = values.getJSONObject(j);
                    String title = ageItem.getString("title");
                    Integer num = ageItem.getInteger("num");

                    QualificationAge info = new QualificationAge();
                    info.setTitle(title);
                    info.setNum(num);
                    info.setType(type);
                    if ("1".equals(type)) {
                        info.setCountyName(name);
                    } else {
                        info.setSchoolName(name);
                    }
                    ApiDbHelper.fillTimestamps(info);

                    ApiDbHelper.insertOrUpdate(qualificationAgeMapper, info, (LambdaQueryWrapper<QualificationAge> wrapper) -> {
                        wrapper.eq(QualificationAge::getTitle, title)
                                .eq(QualificationAge::getType, type);
                        if ("1".equals(type)) {
                            wrapper.eq(QualificationAge::getCountyName, name);
                        } else {
                            wrapper.eq(QualificationAge::getSchoolName, name);
                        }
                        return wrapper;
                    });

                    totalCount++;
                }
            }
        }

        // type = 3 中职（需传 county）
        Result countyListResult = oneFormService.countyList(year);
        List<Map<String, Object>> countyList = (List<Map<String, Object>>) countyListResult.getData();
        for (Map<String, Object> county : countyList) {
            String countyName = Objects.toString(county.get("name"));
            if (StrUtil.isBlank(countyName)) {
                log.warn("跳过无效区县: {}", county);
                continue;
            }

            JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/age", Map.of(
                    "year", year,
                    "type", "3",
                    "county", countyName
            ));

            JSONArray dataList = result.getJSONArray("data");
            if (dataList == null || dataList.isEmpty()) continue;
            JSONArray values = dataList.getJSONObject(0).getJSONArray("value");
            if (values == null) continue;

            for (int j = 0; j < values.size(); j++) {
                JSONObject ageItem = values.getJSONObject(j);
                String title = ageItem.getString("title");
                Integer num = ageItem.getInteger("num");
                if (num == null || num == 0) continue;

                QualificationAge info = new QualificationAge();
                info.setTitle(title);
                info.setNum(num);
                info.setType("3");
                info.setCountyName(countyName);
                ApiDbHelper.fillTimestamps(info);

                ApiDbHelper.insertOrUpdate(qualificationAgeMapper, info, (LambdaQueryWrapper<QualificationAge> wrapper) ->
                        wrapper.eq(QualificationAge::getTitle, title)
                                .eq(QualificationAge::getCountyName, countyName)
                                .eq(QualificationAge::getType, "3")
                );

                totalCount++;
            }
        }

        log.info("年龄结构处理完成，共 {} 条记录", totalCount);
        return Result.success("年龄结构保存完成，共 " + totalCount + " 条记录");
    }

    @Override
    public Result saveTitle(String year) {

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int total = 0;

        for (int t = 1; t <= 2; t++) {
            String type = String.valueOf(t);
            JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/title", Map.of(
                    "year", year,
                    "type", type
            ));

            JSONArray dataList = result.getJSONArray("data");
            if (dataList == null || dataList.isEmpty()) continue;

            for (int i = 0; i < dataList.size(); i++) {
                JSONObject item = dataList.getJSONObject(i);
                String name = item.getString("name");
                if (StrUtil.isBlank(name)) continue;

                ProfessionalTeacher info = new ProfessionalTeacher();
                info.setName(name);
                info.setType(type);
                info.setZgjNum(item.getInteger("zgjNum"));
                info.setFgjNum(item.getInteger("fgjNum"));
                info.setZjNum(item.getInteger("zjNum"));
                info.setCjNum(item.getInteger("cjNum"));
                info.setZljNum(item.getInteger("zljNum"));
                info.setYjNum(item.getInteger("yjNum"));
                info.setWdzjNum(item.getInteger("wdzjNum"));
                ApiDbHelper.fillTimestamps(info);

                ApiDbHelper.insertOrUpdate(professionalTeacherMapper, info, (LambdaQueryWrapper<ProfessionalTeacher> wrapper) ->
                        wrapper.eq(ProfessionalTeacher::getName, name)
                                .eq(ProfessionalTeacher::getType, type)
                );

                total++;
            }
        }

        log.info("职称结构数据保存完成，共 {} 条记录", total);
        return Result.success("职称结构保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveGenderDetail(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) return Result.error("Token 获取失败");

        int total = 0;

        for (int type = 1; type <= 2; type++) {
            JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/genderDetail", Map.of(
                    "year", year,
                    "type", type
            ));

            JSONArray data = result.getJSONArray("data");
            if (data == null || data.isEmpty()) continue;

            for (int i = 0; i < data.size(); i++) {
                JSONObject obj = data.getJSONObject(i);
                String name = obj.getString("name");
                String num = obj.getString("num");
                if (StrUtil.isBlank(name)) continue;

                GenderDetail detail = new GenderDetail();
                detail.setName(name);
                detail.setType(String.valueOf(type));
                detail.setNum(num);
                ApiDbHelper.fillTimestamps(detail);

                int finalType = type;
                ApiDbHelper.insertOrUpdate(genderDetailMapper, detail,
                        (LambdaQueryWrapper<GenderDetail> wrapper) -> wrapper
                                .eq(GenderDetail::getName, name)
                                .eq(GenderDetail::getType, finalType)
                );

                total++;
            }
        }

        log.info("性别比例数据保存完成，共 {} 条记录", total);
        return Result.success("性别比例保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveCountry(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int total = 0;

        // 1. 处理汇总（name 不传）
        JSONObject summaryResult = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/country", Map.of(
                "year", year
        ));

        JSONObject summaryData = summaryResult.getJSONObject("data");
        if (summaryData != null) {
            ProfessionalCountry entity = buildCountryEntity("汇总", summaryData);
            ApiDbHelper.insertOrUpdate(professionalCountryMapper, entity, (LambdaQueryWrapper<ProfessionalCountry> wrapper) ->
                    wrapper.eq(ProfessionalCountry::getName, "汇总")
            );
            total++;
        }

        // 2. 遍历所有区县
        Result countyListResult = oneFormService.countyList(year);
        List<Map<String, Object>> countyList = (List<Map<String, Object>>) countyListResult.getData();
        if (CollUtil.isEmpty(countyList)) {
            log.warn("未获取到区县列表");
            return Result.error("区县列表为空");
        }

        for (Map<String, Object> county : countyList) {
            String name = Objects.toString(county.get("countyName"), null);
            if (StrUtil.isBlank(name)) {
                log.warn("跳过无效区县: {}", county);
                continue;
            }

            JSONObject result = ApiDbHelper.postAndParse(token, ybtConfig.getUrl(), "/api/v1/data/country", Map.of(
                    "year", year,
                    "county", name,
                    "type", "1"
            ));

            JSONObject data = result.getJSONObject("data");
            if (data == null) {
                log.warn("接口未返回数据 [区县: {}]", name);
                continue;
            }

            ProfessionalCountry entity = buildCountryEntity(name, data);
            ApiDbHelper.insertOrUpdate(professionalCountryMapper, entity, (LambdaQueryWrapper<ProfessionalCountry> wrapper) ->
                    wrapper.eq(ProfessionalCountry::getName, name)
            );
            total++;
        }

        log.info("城乡分布数据保存完成，共 {} 条记录", total);
        return Result.success("城乡分布保存完成，共 " + total + " 条记录");
    }

    private ProfessionalCountry buildCountryEntity(String name, JSONObject data) {
        ProfessionalCountry entity = new ProfessionalCountry();
        entity.setName(name);
        entity.setCityNum(data.getInteger("cityNum"));
        entity.setCityRatio(data.getString("cityRatio"));
        entity.setCountyNum(data.getInteger("countyNum"));
        entity.setCountyRatio(data.getString("countyRatio"));
        entity.setVillageNum(data.getInteger("villageNum"));
        entity.setVillageRatio(data.getString("villageRatio"));
        ApiDbHelper.fillTimestamps(entity);
        return entity;
    }

    @Override
    public Result saveCountryDetail(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int total = 0;
        String endpoint = "/api/v1/data/countryDetail";
        String baseUrl = ybtConfig.getUrl();

        String[] typeArray = {
                "汇总", "幼儿阶段", "小学阶段", "初中阶段", "高中阶段", "中职阶段"
        };

        for (String typeStr : typeArray) {
            JSONObject form = new JSONObject();
            form.put("year", year);
            form.put("type", typeStr);

            JSONObject result;
            try {
                result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            } catch (Exception e) {
                log.warn("接口调用失败 [type={}]: {}", typeStr, e.getMessage());
                continue;
            }

            JSONArray dataArray = result.getJSONArray("data");
            if (CollUtil.isEmpty(dataArray)) {
                log.warn("接口返回空数据 [type={}]", typeStr);
                continue;
            }

            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject obj = dataArray.getJSONObject(i);

                CountryDetail detail = new CountryDetail();
                detail.setName(obj.getString("name"));
                detail.setType(typeStr);
                detail.setCityNum(obj.getInteger("cityNum"));
                detail.setCityRatio(obj.getString("cityRatio"));
                detail.setCountyNum(obj.getInteger("countyNum"));
                detail.setCountyRatio(obj.getString("countyRatio"));
                detail.setVillageNum(obj.getInteger("villageNum"));
                detail.setVillageRatio(obj.getString("villageRatio"));
                ApiDbHelper.fillTimestamps(detail);

                ApiDbHelper.insertOrUpdate(countryDetailMapper, detail, (LambdaQueryWrapper<CountryDetail> wrapper) ->
                        wrapper.eq(CountryDetail::getName, detail.getName())
                                .eq(CountryDetail::getType, detail.getType())
                );

                total++;
            }
        }

        log.info("城乡分布详情保存完成，共 {} 条记录", total);
        return Result.success("城乡分布详情保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveInstructorDetail(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        String endpoint = "/api/v1/data/instructorDetail";
        String baseUrl = ybtConfig.getUrl();

        JSONObject form = new JSONObject();
        form.put("year", year);
        JSONObject result;
        try {
            result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
        } catch (Exception e) {
            log.error("辅导员详情接口调用失败: {}", e.getMessage());
            return Result.error("辅导员详情接口调用失败");
        }

        JSONArray dataArray = result.getJSONArray("data");
        if (CollUtil.isEmpty(dataArray)) {
            log.warn("辅导员详情接口返回空数据");
            return Result.error("接口返回空数据");
        }

        int total = 0;
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject obj = dataArray.getJSONObject(i);

            CounselorsDetail detail = new CounselorsDetail();
            detail.setName(obj.getString("name"));
            detail.setNum(obj.getIntValue("num"));
            detail.setShortfall(obj.getIntValue("shortfall"));
            ApiDbHelper.fillTimestamps(detail);

            ApiDbHelper.insertOrUpdate(counselorsDetailMapper, detail, (LambdaQueryWrapper<CounselorsDetail> wrapper) ->
                    wrapper.eq(CounselorsDetail::getName, detail.getName())
            );

            total++;
        }

        log.info("辅导员数量详情保存完成，共 {} 条记录", total);
        return Result.success("辅导员数量详情保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveCourses(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("参数 year 不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int total = 0;
        String endpoint = "/api/v1/data/courses";
        String baseUrl = ybtConfig.getUrl();

        // ------- 1. 处理汇总数据 -------
        JSONObject summaryForm = new JSONObject();
        summaryForm.put("year", year);

        try {
            JSONObject summaryResult = ApiDbHelper.postAndParse(token, baseUrl, endpoint, summaryForm);
            JSONObject data = summaryResult.getJSONObject("data");
            if (data != null && !data.isEmpty()) {
                ProfessionalCourses summary = new ProfessionalCourses();
                summary.setName("汇总");
                summary.setType("0");
                summary.setSmallSchool(data.getInteger("primary"));
                summary.setJunior(data.getInteger("junior"));
                summary.setSenior(data.getInteger("senior"));
                summary.setVocational(data.getInteger("vocational"));
                summary.setPrimaryGap(data.getInteger("primaryGap"));
                summary.setJuniorGap(data.getInteger("juniorGap"));
                summary.setSeniorGap(data.getInteger("seniorGap"));
                summary.setVocationalGap(data.getInteger("vocationalGap"));
                ApiDbHelper.fillTimestamps(summary);

                ApiDbHelper.insertOrUpdate(professionalCoursesMapper, summary, (LambdaQueryWrapper<ProfessionalCourses> wrapper) ->
                        wrapper.eq(ProfessionalCourses::getName, "汇总")
                                .eq(ProfessionalCourses::getType, "0")
                );
                total++;
            }
        } catch (Exception e) {
            log.warn("调用汇总数据失败: {}", e.getMessage());
        }

        // ------- 2. 处理区县数据 type=1 -------
        Result countyListResult = oneFormService.countyList(year);
        if (countyListResult.getCode() == 200 && countyListResult.getData() instanceof List) {
            List<JSONObject> rawCountyList = (List<JSONObject>) countyListResult.getData();
            List<String> countyNames = rawCountyList.stream()
                    .map(obj -> obj.getString("countyName"))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());

            for (String name : countyNames) {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 1);
                form.put("name", name);

                try {
                    JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                    JSONObject data = result.getJSONObject("data");
                    if (data == null || data.isEmpty()) continue;

                    ProfessionalCourses entity = new ProfessionalCourses();
                    entity.setName(name);
                    entity.setType("1");
                    entity.setSmallSchool(data.getInteger("primary"));
                    entity.setJunior(data.getInteger("junior"));
                    entity.setSenior(data.getInteger("senior"));
                    entity.setVocational(data.getInteger("vocational"));
                    entity.setPrimaryGap(data.getInteger("primaryGap"));
                    entity.setJuniorGap(data.getInteger("juniorGap"));
                    entity.setSeniorGap(data.getInteger("seniorGap"));
                    entity.setVocationalGap(data.getInteger("vocationalGap"));
                    ApiDbHelper.fillTimestamps(entity);

                    ApiDbHelper.insertOrUpdate(professionalCoursesMapper, entity, (LambdaQueryWrapper<ProfessionalCourses> wrapper) ->
                            wrapper.eq(ProfessionalCourses::getName, name)
                                    .eq(ProfessionalCourses::getType, "1")
                    );
                    total++;
                } catch (Exception e) {
                    log.warn("调用区县数据失败 [name={}]: {}", name, e.getMessage());
                }
            }
        }

        // ------- 3. 处理高校数据 type=2 -------
        Result highListResult = oneFormService.highList(year);
        if (highListResult.getCode() == 200 && highListResult.getData() instanceof List) {
            List<JSONObject> rawHighList = (List<JSONObject>) highListResult.getData();
            List<String> highNames = rawHighList.stream()
                    .map(obj -> obj.getString("orgnazitionName"))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());

            for (String name : highNames) {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 2);
                form.put("name", name);

                try {
                    JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                    JSONObject data = result.getJSONObject("data");
                    if (data == null || data.isEmpty()) continue;

                    ProfessionalCourses entity = new ProfessionalCourses();
                    entity.setName(name);
                    entity.setType("2");
                    entity.setHigh(data.getInteger("high"));
                    entity.setHighGap(data.getInteger("highGap"));
                    ApiDbHelper.fillTimestamps(entity);

                    ApiDbHelper.insertOrUpdate(professionalCoursesMapper, entity, (LambdaQueryWrapper<ProfessionalCourses> wrapper) ->
                            wrapper.eq(ProfessionalCourses::getName, name)
                                    .eq(ProfessionalCourses::getType, "2")
                    );
                    total++;
                } catch (Exception e) {
                    log.warn("调用高校数据失败 [name={}]: {}", name, e.getMessage());
                }
            }
        }

        log.info("专职思政课教师数据保存完成，共 {} 条", total);
        return Result.success("专职思政课教师数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveCoursesDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        int total = 0;
        String endpoint = "/api/v1/data/coursesDetail";
        String baseUrl = ybtConfig.getUrl();

        // -------- 1. 处理 type=1 区县数据 --------
        JSONObject form = new JSONObject();
        form.put("year", year);
        form.put("type", 1);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    CoursesDetail detail = new CoursesDetail();
                    detail.setName(item.getString("name"));
                    detail.setType("1");
                    detail.setSmallSchool(item.getInteger("primary"));
                    detail.setJunior(item.getInteger("junior"));
                    detail.setSenior(item.getInteger("senior"));
                    detail.setVocational(item.getInteger("vocational"));

                    ApiDbHelper.fillTimestamps(detail);
                    ApiDbHelper.insertOrUpdate(coursesDetailMapper, detail, (LambdaQueryWrapper<CoursesDetail> wrapper) ->
                            wrapper.eq(CoursesDetail::getName, detail.getName())
                                    .eq(CoursesDetail::getType, "1")
                    );
                    total++;
                }
            }
        } catch (Exception e) {
            log.error("获取区县课程详情失败：{}", e.getMessage());
        }

        // -------- 2. 处理 type=2 高校数据 --------
        JSONObject form2 = new JSONObject();
        form2.put("year", year);
        form2.put("type", 2);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form2);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    CoursesDetail detail = new CoursesDetail();
                    detail.setName(item.getString("name"));
                    detail.setType("2");
                    detail.setHigh(item.getInteger("high"));

                    ApiDbHelper.fillTimestamps(detail);
                    ApiDbHelper.insertOrUpdate(coursesDetailMapper, detail, (LambdaQueryWrapper<CoursesDetail> wrapper) ->
                            wrapper.eq(CoursesDetail::getName, detail.getName())
                                    .eq(CoursesDetail::getType, "2")
                    );
                    total++;
                }
            }
        } catch (Exception e) {
            log.error("获取高校课程详情失败：{}", e.getMessage());
        }

        log.info("课程详情数据保存完成，共 {} 条", total);
        return Result.success("课程详情数据保存完成，共 " + total + " 条");
    }

    @Override
    public Result savePsychology(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("参数 year 不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("TokenManager 返回 null");
            return Result.error("获取 Token 失败");
        }

        int total = 0;
        String endpoint = "/api/v1/data/psychology";
        String baseUrl = ybtConfig.getUrl();

        // ------- 1. 处理汇总数据 -------
        JSONObject summaryForm = new JSONObject();
        summaryForm.put("year", year);

        try {
            JSONObject summaryResult = ApiDbHelper.postAndParse(token, baseUrl, endpoint, summaryForm);
            JSONObject data = summaryResult.getJSONObject("data");
            if (data != null && !data.isEmpty()) {
                ProfessionalPsychology summary = new ProfessionalPsychology();
                summary.setName("汇总");
                summary.setType("0");
                summary.setSmallSchool(data.getInteger("primary"));
                summary.setJunior(data.getInteger("junior"));
                summary.setSenior(data.getInteger("senior"));
                summary.setVocational(data.getInteger("vocational"));
                summary.setPrimaryGap(data.getInteger("primaryGap"));
                summary.setJuniorGap(data.getInteger("juniorGap"));
                summary.setSeniorGap(data.getInteger("seniorGap"));
                summary.setVocationalGap(data.getInteger("vocationalGap"));
                ApiDbHelper.fillTimestamps(summary);

                ApiDbHelper.insertOrUpdate(professionalPsychologyMapper, summary, (LambdaQueryWrapper<ProfessionalPsychology> wrapper) ->
                        wrapper.eq(ProfessionalPsychology::getName, "汇总")
                                .eq(ProfessionalPsychology::getType, "0")
                );
                total++;
            }
        } catch (Exception e) {
            log.warn("调用汇总数据失败: {}", e.getMessage());
        }

        // ------- 2. 处理区县数据 type=1 -------
        Result countyListResult = oneFormService.countyList(year);
        if (countyListResult.getCode() == 200 && countyListResult.getData() instanceof List) {
            List<JSONObject> rawCountyList = (List<JSONObject>) countyListResult.getData();
            List<String> countyNames = rawCountyList.stream()
                    .map(obj -> obj.getString("countyName"))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());

            for (String name : countyNames) {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 1);
                form.put("name", name);

                try {
                    JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                    JSONObject data = result.getJSONObject("data");
                    if (data == null || data.isEmpty()) continue;

                    ProfessionalPsychology entity = new ProfessionalPsychology();
                    entity.setName(name);
                    entity.setType("1");
                    entity.setSmallSchool(data.getInteger("primary"));
                    entity.setJunior(data.getInteger("junior"));
                    entity.setSenior(data.getInteger("senior"));
                    entity.setVocational(data.getInteger("vocational"));
                    entity.setPrimaryGap(data.getInteger("primaryGap"));
                    entity.setJuniorGap(data.getInteger("juniorGap"));
                    entity.setSeniorGap(data.getInteger("seniorGap"));
                    entity.setVocationalGap(data.getInteger("vocationalGap"));
                    ApiDbHelper.fillTimestamps(entity);

                    ApiDbHelper.insertOrUpdate(professionalPsychologyMapper, entity, (LambdaQueryWrapper<ProfessionalPsychology> wrapper) ->
                            wrapper.eq(ProfessionalPsychology::getName, name)
                                    .eq(ProfessionalPsychology::getType, "1")
                    );
                    total++;
                } catch (Exception e) {
                    log.warn("调用区县数据失败 [name={}]: {}", name, e.getMessage());
                }
            }
        }

        // ------- 3. 处理高校数据 type=2 -------
        Result highListResult = oneFormService.highList(year);
        if (highListResult.getCode() == 200 && highListResult.getData() instanceof List) {
            List<JSONObject> rawHighList = (List<JSONObject>) highListResult.getData();
            List<String> highNames = rawHighList.stream()
                    .map(obj -> obj.getString("orgnazitionName"))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());

            for (String name : highNames) {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 2);
                form.put("name", name);

                try {
                    JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                    JSONObject data = result.getJSONObject("data");
                    if (data == null || data.isEmpty()) continue;

                    ProfessionalPsychology entity = new ProfessionalPsychology();
                    entity.setName(name);
                    entity.setType("2");
                    entity.setHigh(data.getInteger("high"));
                    entity.setHighGap(data.getInteger("highGap"));
                    ApiDbHelper.fillTimestamps(entity);

                    ApiDbHelper.insertOrUpdate(professionalPsychologyMapper, entity, (LambdaQueryWrapper<ProfessionalPsychology> wrapper) ->
                            wrapper.eq(ProfessionalPsychology::getName, name)
                                    .eq(ProfessionalPsychology::getType, "2")
                    );
                    total++;
                } catch (Exception e) {
                    log.warn("调用高校数据失败 [name={}]: {}", name, e.getMessage());
                }
            }
        }

        log.info("专职思政课教师数据保存完成，共 {} 条", total);
        return Result.success("专职思政课教师数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result savePsychologyDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        int total = 0;
        String endpoint = "/api/v1/data/psychologyDetail";
        String baseUrl = ybtConfig.getUrl();

        // -------- 1. 处理 type=1 区县数据 --------
        JSONObject form = new JSONObject();
        form.put("year", year);
        form.put("type", 1);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    PsychologyDetail detail = new PsychologyDetail();
                    detail.setName(item.getString("name"));
                    detail.setType("1");
                    detail.setSmallSchool(item.getInteger("primary"));
                    detail.setJunior(item.getInteger("junior"));
                    detail.setSenior(item.getInteger("senior"));

                    ApiDbHelper.fillTimestamps(detail);
                    ApiDbHelper.insertOrUpdate(psychologyDetailMapper, detail, (LambdaQueryWrapper<PsychologyDetail> wrapper) ->
                            wrapper.eq(PsychologyDetail::getName, detail.getName())
                                    .eq(PsychologyDetail::getType, "1")
                    );
                    total++;
                }
            }
        } catch (Exception e) {
            log.error("获取区县课程详情失败：{}", e.getMessage());
        }

        // -------- 2. 处理 type=2 高校数据 --------
        JSONObject form2 = new JSONObject();
        form2.put("year", year);
        form2.put("type", 2);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form2);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    PsychologyDetail detail = new PsychologyDetail();
                    detail.setName(item.getString("name"));
                    detail.setType("2");
                    detail.setHigh(item.getInteger("high"));

                    ApiDbHelper.fillTimestamps(detail);
                    ApiDbHelper.insertOrUpdate(psychologyDetailMapper, detail, (LambdaQueryWrapper<PsychologyDetail> wrapper) ->
                            wrapper.eq(PsychologyDetail::getName, detail.getName())
                                    .eq(PsychologyDetail::getType, "2")
                    );
                    total++;
                }
            }
        } catch (Exception e) {
            log.error("获取高校课程详情失败：{}", e.getMessage());
        }

        log.info("课程详情数据保存完成，共 {} 条", total);
        return Result.success("课程详情数据保存完成，共 " + total + " 条");
    }

    @Override
    public Result saveSchoolNum(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/schoolNum";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        JSONObject form = new JSONObject();
        form.put("year", year);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);
                    SchoolNum schoolNum = new SchoolNum();
                    schoolNum.setOrganizationName(item.getString("organizationName"));
                    schoolNum.setSchoolNum(item.getInteger("schoolNum"));
                    schoolNum.setTeacherNum(item.getInteger("teacherNum"));
                    schoolNum.setStudentNum(item.getInteger("studentNum"));

                    ApiDbHelper.fillTimestamps(schoolNum);

                    ApiDbHelper.insertOrUpdate(schoolNumMapper, schoolNum, (LambdaQueryWrapper<SchoolNum> wrapper) ->
                            wrapper.eq(SchoolNum::getOrganizationName, schoolNum.getOrganizationName())
                    );

                    total++;
                }
            }
        } catch (Exception e) {
            log.error("调用学校数量接口失败：{}", e.getMessage());
            return Result.error("调用接口失败：" + e.getMessage());
        }

        log.info("各区县学校、教师、学生数据保存完成，共 {} 条", total);
        return Result.success("各区县学校、教师、学生数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveTeacherList(String year) {
        CompletableFuture.runAsync(() -> saveTeacherListAsync(year));
        return Result.success("教师数据入库任务已提交后台执行");
    }

    @Async
    public void saveTeacherListAsync(String year) {
        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            log.error("获取 token 失败，year={}", year);
            return;
        }

        String endpoint = "/api/v1/data/teacherList";
        String baseUrl = ybtConfig.getUrl();

        int pageNum = 1;
        int pageSize = 500;
        int totalFromApi = 0;

        AtomicInteger insertCount = new AtomicInteger();
        AtomicInteger updateCount = new AtomicInteger();

        while (true) {
            log.info("正在请求教师数据第 {} 页...", pageNum);

            JSONObject form = new JSONObject();
            form.put("year", year);
            form.put("pageNum", pageNum);
            form.put("pageSize", pageSize);

            JSONObject result;
            try {
                result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                log.info("第 {} 页接口返回数据：{}", pageNum, result.toJSONString());
            } catch (Exception e) {
                log.error("请求第 {} 页失败：{}", pageNum, e.getMessage());
                break;
            }

            if (result == null || result.getIntValue("code") != 0) {
                log.error("接口返回错误，第 {} 页，code: {}", pageNum, result != null ? result.getIntValue("code") : "null");
                break;
            }

            JSONObject dataObj = result.getJSONObject("data");
            if (dataObj == null) {
                log.error("第 {} 页 data 字段为空", pageNum);
                break;
            }

            if (pageNum == 1) {
                totalFromApi = dataObj.getIntValue("total");
                log.info("接口报告总记录数：{}", totalFromApi);
            }

            JSONArray data = dataObj.getJSONArray("data");
            if (data == null || data.isEmpty()) {
                log.info("第 {} 页数据为空，结束分页", pageNum);
                break;
            }

            for (int i = 0; i < data.size(); i++) {
                JSONObject item = data.getJSONObject(i);
                TeacherList teacher = new TeacherList();
                teacher.setSchoolName(item.getString("schoolName"));
                teacher.setXxjgbsm(item.getString("xxjgbsm"));
                teacher.setXm(item.getString("xm"));
                teacher.setSsdw(item.getString("ssdw"));
                teacher.setGwlb(item.getString("gwlb"));

                String prsjStr = item.getString("prsj");
                if (StrUtil.isNotBlank(prsjStr)) {
                    try {
                        teacher.setPrsj(DateUtil.parse(prsjStr, "yyyy-MM"));
                    } catch (Exception e) {
                        log.warn("解析聘任时间失败：{}，跳过该字段", prsjStr);
                    }
                }

                ApiDbHelper.fillTimestamps(teacher);

                LambdaQueryWrapper<TeacherList> wrapper = Wrappers.lambdaQuery();
                wrapper.eq(TeacherList::getXxjgbsm, teacher.getXxjgbsm())
                        .eq(TeacherList::getXm, teacher.getXm())
                        .eq(TeacherList::getPrsj, teacher.getPrsj());

                List<TeacherList> exists = teacherListMapper.selectList(wrapper);
                if (exists.isEmpty()) {
                    teacherListMapper.insert(teacher);
                    insertCount.incrementAndGet();
                } else {
                    teacherListMapper.update(teacher, wrapper);
                    updateCount.incrementAndGet();
                }
            }

            if (data.size() < pageSize) break;
            pageNum++;
        }

        int totalHandled = insertCount.get() + updateCount.get();
        log.info("教师数据保存完成，year={}，接口总数：{}，插入：{} 条，更新：{} 条，处理总数：{} 条",
                year, totalFromApi, insertCount.get(), updateCount.get(), totalHandled);
    }

    @Override
    public Result saveInduction(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/induction";
        int total = 0;

        // 1. 全市汇总
        JSONObject form = new JSONObject();
        form.put("year", year);
        JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
        JSONObject data = result.getJSONObject("data");

        TeacherInduction totalStat = new TeacherInduction();
        totalStat.setSchoolName("全市汇总");
        totalStat.setTotal(data.getIntValue("total"));
        totalStat.setHighNum(data.getIntValue("highNum"));
        totalStat.setCountyNum(data.getIntValue("countyNum"));
        totalStat.setPercent(data.getString("percent"));
        totalStat.setHighPercent(data.getString("highPercent"));
        totalStat.setCountyPercent(data.getString("countyPercent"));
        ApiDbHelper.fillTimestamps(totalStat);
        ApiDbHelper.insertOrUpdate(teacherInductionMapper, totalStat,
                wrapper -> wrapper.eq(TeacherInduction::getSchoolName, "全市汇总"));
        total++;

        // 2. 高校汇总
        JSONObject highForm = new JSONObject();
        highForm.put("year", year);
        highForm.put("type", 2);
        result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, highForm);
        data = result.getJSONObject("data");

        TeacherInduction highStat = new TeacherInduction();
        highStat.setSchoolName("高校汇总");
        highStat.setTotal(data.getIntValue("total"));
        highStat.setHighNum(data.getIntValue("highNum"));
        highStat.setHighPercent(data.getString("highPercent"));
        highStat.setPercent(data.getString("percent"));
        ApiDbHelper.fillTimestamps(highStat);
        ApiDbHelper.insertOrUpdate(teacherInductionMapper, highStat,
                wrapper -> wrapper.eq(TeacherInduction::getSchoolName, "高校汇总"));
        total++;

        // 3. 区县汇总
        JSONObject countyForm = new JSONObject();
        countyForm.put("year", year);
        countyForm.put("type", 1);
        result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, countyForm);
        data = result.getJSONObject("data");

        TeacherInduction countyStat = new TeacherInduction();
        countyStat.setSchoolName("区县汇总");
        countyStat.setTotal(data.getIntValue("total"));
        countyStat.setCountyNum(data.getIntValue("countyNum"));
        countyStat.setCountyPercent(data.getString("countyPercent"));
        countyStat.setPercent(data.getString("percent"));
        ApiDbHelper.fillTimestamps(countyStat);
        ApiDbHelper.insertOrUpdate(teacherInductionMapper, countyStat,
                wrapper -> wrapper.eq(TeacherInduction::getSchoolName, "区县汇总"));
        total++;

        // 4. 遍历区县明细
        Result countyResult = oneFormService.countyList(year);
        JSONArray countyArray = (JSONArray) countyResult.getData();
        for (int i = 0; i < countyArray.size(); i++) {
            JSONObject obj = countyArray.getJSONObject(i);
            String countyName = obj.getString("countyName");

            JSONObject detailForm = new JSONObject();
            detailForm.put("year", year);
            detailForm.put("type", 1);
            detailForm.put("name", countyName);

            result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, detailForm);
            data = result.getJSONObject("data");

            TeacherInduction detail = new TeacherInduction();
            detail.setSchoolName(countyName);
            detail.setTotal(data.getIntValue("total"));
            detail.setCountyNum(data.getIntValue("countyNum"));
            detail.setCountyPercent(data.getString("countyPercent"));
            detail.setPercent(data.getString("percent"));
            ApiDbHelper.fillTimestamps(detail);
            ApiDbHelper.insertOrUpdate(teacherInductionMapper, detail,
                    wrapper -> wrapper.eq(TeacherInduction::getSchoolName, countyName));
            total++;
        }

        // 5. 遍历高校明细
        Result schoolResult = oneFormService.highList(year);
        JSONArray schoolArray = (JSONArray) schoolResult.getData();
        for (int i = 0; i < schoolArray.size(); i++) {
            JSONObject obj = schoolArray.getJSONObject(i);
            String schoolName = obj.getString("orgnazitionName");

            JSONObject detailForm = new JSONObject();
            detailForm.put("year", year);
            detailForm.put("type", 2);
            detailForm.put("orgnazitionName", schoolName);

            result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, detailForm);
            data = result.getJSONObject("data");

            TeacherInduction detail = new TeacherInduction();
            detail.setSchoolName(schoolName);
            detail.setTotal(data.getIntValue("total"));
            detail.setHighNum(data.getIntValue("highNum"));
            detail.setHighPercent(data.getString("highPercent"));
            ApiDbHelper.fillTimestamps(detail);
            ApiDbHelper.insertOrUpdate(teacherInductionMapper, detail,
                    wrapper -> wrapper.eq(TeacherInduction::getSchoolName, schoolName));
            total++;
        }

        log.info("年度新入职教师数据保存完成，共 {} 条", total);
        return Result.success("入库成功，共 " + total + " 条记录");
    }

    @Override
    public Result saveInductionDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/inductionDetail";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        try {
            // 处理 type = 1（区县）
            JSONObject form1 = new JSONObject();
            form1.put("year", year);
            form1.put("type", 1);

            JSONObject result1 = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form1);
            JSONArray data1 = result1.getJSONArray("data");

            if (CollUtil.isNotEmpty(data1)) {
                for (int i = 0; i < data1.size(); i++) {
                    JSONObject item = data1.getJSONObject(i);
                    InductionDetail detail = new InductionDetail();
                    detail.setName(item.getString("name"));
                    detail.setKindergarten(item.getInteger("kindergarten"));
                    detail.setSmallSchool(item.getInteger("primary"));
                    detail.setJunior(item.getInteger("junior"));
                    detail.setSenior(item.getInteger("senior"));
                    detail.setVocational(item.getInteger("vocational"));

                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(inductionDetailMapper, detail, (LambdaQueryWrapper<InductionDetail> wrapper) ->
                            wrapper.eq(InductionDetail::getName, detail.getName())
                    );

                    total++;
                }
            }

            // 处理 type = 2（高校）
            JSONObject form2 = new JSONObject();
            form2.put("year", year);
            form2.put("type", 2);

            JSONObject result2 = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form2);
            JSONArray data2 = result2.getJSONArray("data");

            if (CollUtil.isNotEmpty(data2)) {
                for (int i = 0; i < data2.size(); i++) {
                    JSONObject item = data2.getJSONObject(i);
                    InductionDetail detail = new InductionDetail();
                    detail.setName(item.getString("name"));
                    detail.setNum(item.getInteger("num"));

                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(inductionDetailMapper, detail, (LambdaQueryWrapper<InductionDetail> wrapper) ->
                            wrapper.eq(InductionDetail::getName, detail.getName())
                    );

                    total++;
                }
            }
        } catch (Exception e) {
            log.error("保存新入职教师详情失败：{}", e.getMessage(), e);
            return Result.error("保存失败：" + e.getMessage());
        }

        log.info("新入职教师详情数据保存完成，共 {} 条", total);
        return Result.success("新入职教师详情数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveTwoProfession(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/twoProfession";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        try {

            // 区县汇总
            JSONObject countyTotalForm = new JSONObject();
            countyTotalForm.put("year", year);
            countyTotalForm.put("type", 1);
            countyTotalForm.put("countyName", "汇总");

            JSONObject resultCountyTotal = ApiDbHelper.postAndParse(token, baseUrl, endpoint, countyTotalForm);
            JSONObject dataCountyTotal = resultCountyTotal.getJSONObject("data");
            if (CollUtil.isNotEmpty(dataCountyTotal)) {
                TwoProfession entity = new TwoProfession();
                entity.setName("区县汇总");
                entity.setTotal(dataCountyTotal.getInteger("total"));
                entity.setPercent(dataCountyTotal.getString("percent"));
                entity.setOnVocational(dataCountyTotal.getInteger("onVocational"));
                entity.setUnVocational(dataCountyTotal.getInteger("unVocational"));
                entity.setVocationalPercent(dataCountyTotal.getString("vocationalPercent"));
                entity.setOnHigh(dataCountyTotal.getInteger("onHigh"));
                entity.setUnHigh(dataCountyTotal.getInteger("unHigh"));
                entity.setHighPercent(dataCountyTotal.getString("highPercent"));

                ApiDbHelper.fillTimestamps(entity);
                ApiDbHelper.insertOrUpdate(twoProfessionMapper, entity,
                        wrapper -> wrapper.eq(TwoProfession::getName, entity.getName()));
                total++;
            }

            //  高校汇总
            JSONObject collegeTotalForm = new JSONObject();
            collegeTotalForm.put("year", year);
            collegeTotalForm.put("type", 2);

            JSONObject resultCollegeTotal = ApiDbHelper.postAndParse(token, baseUrl, endpoint, collegeTotalForm);
            JSONObject dataCollegeTotal = resultCollegeTotal.getJSONObject("data");
            if (CollUtil.isNotEmpty(dataCollegeTotal)) {
                TwoProfession entity = new TwoProfession();
                entity.setName("高校汇总");
                entity.setTotal(dataCollegeTotal.getInteger("total"));
                entity.setPercent(dataCollegeTotal.getString("percent"));
                entity.setOnVocational(dataCollegeTotal.getInteger("onVocational"));
                entity.setUnVocational(dataCollegeTotal.getInteger("unVocational"));
                entity.setVocationalPercent(dataCollegeTotal.getString("vocationalPercent"));
                entity.setOnHigh(dataCollegeTotal.getInteger("onHigh"));
                entity.setUnHigh(dataCollegeTotal.getInteger("unHigh"));
                entity.setHighPercent(dataCollegeTotal.getString("highPercent"));

                ApiDbHelper.fillTimestamps(entity);
                ApiDbHelper.insertOrUpdate(twoProfessionMapper, entity,
                        wrapper -> wrapper.eq(TwoProfession::getName, entity.getName()));
                total++;
            }

            // === 2. 区县明细 ===
            Result countyResult = oneFormService.countyList(year);
            if (countyResult == null || countyResult.getCode() != 200) {
                return Result.error("获取区县列表失败：" + (countyResult != null ? countyResult.getMessage() : "返回为空"));
            }

            JSONArray countyArray = (JSONArray) countyResult.getData();
            List<String> countyList = new ArrayList<>();
            for (int i = 0; i < countyArray.size(); i++) {
                JSONObject item = countyArray.getJSONObject(i);
                String name = item.getString("countyName");
                if (StrUtil.isNotBlank(name)) {
                    countyList.add(name);
                }
            }

            for (String county : countyList) {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 1);
                form.put("name", county);

                JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                JSONObject data = result.getJSONObject("data");

                if (CollUtil.isNotEmpty(data)) {
                    TwoProfession entity = new TwoProfession();
                    entity.setName(county);
                    entity.setTotal(data.getInteger("total"));
                    entity.setPercent(data.getString("percent"));
                    entity.setOnVocational(data.getInteger("onVocational"));
                    entity.setUnVocational(data.getInteger("unVocational"));
                    entity.setVocationalPercent(data.getString("vocationalPercent"));
                    entity.setOnHigh(data.getInteger("onHigh"));
                    entity.setUnHigh(data.getInteger("unHigh"));
                    entity.setHighPercent(data.getString("highPercent"));

                    ApiDbHelper.fillTimestamps(entity);
                    ApiDbHelper.insertOrUpdate(twoProfessionMapper, entity,
                            wrapper -> wrapper.eq(TwoProfession::getName, entity.getName()));
                    total++;
                }
            }

            // === 3. 高校明细 ===
            Result collegeListResult = oneFormService.highList(year);
            if (collegeListResult == null || collegeListResult.getCode() != 200) {
                return Result.error("获取高校列表失败：" + (collegeListResult != null ? collegeListResult.getMessage() : "返回为空"));
            }

            List<Map<String, Object>> collegeList = (List<Map<String, Object>>) collegeListResult.getData();
            if (collegeList == null) collegeList = new ArrayList<>();

            for (Map<String, Object> college : collegeList) {
                String schoolName = Objects.toString(college.get("orgnazitionName"), null);
                if (StrUtil.isBlank(schoolName)) {
                    log.warn("高校名称为空，跳过");
                    continue;
                }

                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 2);
                form.put("name", schoolName);

                JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                JSONObject data = result.getJSONObject("data");

                if (CollUtil.isNotEmpty(data)) {
                    TwoProfession entity = new TwoProfession();
                    entity.setName(schoolName);
                    entity.setTotal(data.getInteger("total"));
                    entity.setPercent(data.getString("percent"));
                    entity.setOnVocational(data.getInteger("onVocational"));
                    entity.setUnVocational(data.getInteger("unVocational"));
                    entity.setVocationalPercent(data.getString("vocationalPercent"));
                    entity.setOnHigh(data.getInteger("onHigh"));
                    entity.setUnHigh(data.getInteger("unHigh"));
                    entity.setHighPercent(data.getString("highPercent"));

                    ApiDbHelper.fillTimestamps(entity);
                    ApiDbHelper.insertOrUpdate(twoProfessionMapper, entity,
                            wrapper -> wrapper.eq(TwoProfession::getName, entity.getName()));
                    total++;
                }
            }

        } catch (Exception e) {
            log.error("保存职业院校双师型教师数据失败：{}", e.getMessage(), e);
            return Result.error("保存失败：" + e.getMessage());
        }

        log.info("职业院校双师型教师数据保存完成，共 {} 条", total);
        return Result.success("职业院校双师型教师数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveTwoProfessionDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/twoProfessionDetail";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        try {
            // === 1. 处理 type = 1（区县）
            JSONObject formCounty = new JSONObject();
            formCounty.put("year", year);
            formCounty.put("type", 1);

            JSONObject resultCounty = ApiDbHelper.postAndParse(token, baseUrl, endpoint, formCounty);
            JSONArray countyData = resultCounty.getJSONArray("data");

            if (CollUtil.isNotEmpty(countyData)) {
                for (int i = 0; i < countyData.size(); i++) {
                    JSONObject item = countyData.getJSONObject(i);

                    ProfessionDetail professionDetail = new ProfessionDetail();
                    professionDetail.setName(item.getString("name"));
                    professionDetail.setNum(item.getInteger("num"));
                    professionDetail.setPercent(item.getString("percent"));

                    ApiDbHelper.fillTimestamps(professionDetail);

                    ApiDbHelper.insertOrUpdate(professionDetailMapper, professionDetail, wrapper ->
                            wrapper.eq(ProfessionDetail::getName, professionDetail.getName())
                    );

                    total++;
                }
            }

            // === 2. 处理 type = 2（高校）
            Result highListResult = oneFormService.highList(year);
            if (highListResult == null || highListResult.getCode() != 200) {
                return Result.error("获取高校列表失败：" + (highListResult != null ? highListResult.getMessage() : "返回为空"));
            }

            List<Map<String, Object>> collegeList = (List<Map<String, Object>>) highListResult.getData();
            if (collegeList == null) collegeList = new ArrayList<>();

            for (Map<String, Object> college : collegeList) {
                String organizationName = Objects.toString(college.get("orgnazitionName"), null);
                if (StrUtil.isBlank(organizationName)) continue;

                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 2);
                form.put("name", organizationName);

                log.info("请求高校 [{}] 双师型详情参数：{}", organizationName, form.toJSONString());

                JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                JSONArray dataList = result.getJSONArray("data");

                if (CollUtil.isEmpty(dataList)) {
                    // 即使没有数据，也要保存 0
                    ProfessionDetail emptyEntity = new ProfessionDetail();
                    emptyEntity.setName(organizationName);
                    emptyEntity.setNum(0);
                    emptyEntity.setPercent("0%");
                    ApiDbHelper.fillTimestamps(emptyEntity);

                    ApiDbHelper.insertOrUpdate(professionDetailMapper, emptyEntity, wrapper ->
                            wrapper.eq(ProfessionDetail::getName, organizationName)
                    );
                    total++;
                    continue;
                }

                for (int i = 0; i < dataList.size(); i++) {
                    JSONObject item = dataList.getJSONObject(i);
                    ProfessionDetail entity = new ProfessionDetail();
                    entity.setName(organizationName);
                    entity.setNum(item.getInteger("num"));
                    entity.setPercent(item.getString("percent"));
                    ApiDbHelper.fillTimestamps(entity);

                    ApiDbHelper.insertOrUpdate(professionDetailMapper, entity, wrapper ->
                            wrapper.eq(ProfessionDetail::getName, organizationName)
                    );
                    total++;
                }
            }

        } catch (Exception e) {
            log.error("保存职业院校双师型教师详情失败：{}", e.getMessage(), e);
            return Result.error("保存失败：" + e.getMessage());
        }

        log.info("职业院校双师型教师详情数据保存完成，共 {} 条", total);
        return Result.success("职业院校双师型教师详情数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveArtisticDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/artisticDetail";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        JSONObject form = new JSONObject();
        form.put("year", year);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);

                    ArtisticDetail detail = new ArtisticDetail();
                    detail.setName(item.getString("name"));
                    detail.setSportsNum(item.getInteger("sportsNum"));
                    detail.setArtsNum(item.getInteger("artsNum"));

                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(artisticDetailMapper, detail, (LambdaQueryWrapper<ArtisticDetail> wrapper) ->
                            wrapper.eq(ArtisticDetail::getName, detail.getName())
                    );

                    total++;
                }
            }

        } catch (Exception e) {
            log.error("调用艺体类教师接口失败：{}", e.getMessage(), e);
            return Result.error("调用接口失败：" + e.getMessage());
        }

        log.info("艺体类教师详情数据保存完成，共 {} 条", total);
        return Result.success("艺体类教师详情数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveDoctorDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/doctorDetail";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        JSONObject form = new JSONObject();
        form.put("year", year);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONArray data = result.getJSONArray("data");

            if (data != null && !data.isEmpty()) {
                for (int i = 0; i < data.size(); i++) {
                    JSONObject item = data.getJSONObject(i);

                    DoctorDetail detail = new DoctorDetail();
                    detail.setName(item.getString("name"));
                    detail.setPercent(item.getString("percent"));

                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(doctorDetailMapper, detail, (LambdaQueryWrapper<DoctorDetail> wrapper) ->
                            wrapper.eq(DoctorDetail::getName, detail.getName())
                    );

                    total++;
                }
            }

        } catch (Exception e) {
            log.error("调用博士占比接口失败：{}", e.getMessage(), e);
            return Result.error("调用接口失败：" + e.getMessage());
        }

        log.info("普通本科高校博士占比数据保存完成，共 {} 条", total);
        return Result.success("普通本科高校博士占比数据保存完成，共 " + total + " 条记录");
    }

    @Override
    public Result saveTraining(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/training";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        // 汇总数据
        total += fetchAndSaveTraining(token, baseUrl, endpoint, year, null, null, "汇总");

        // 区县汇总数据
        total += fetchAndSaveTraining(token, baseUrl, endpoint, year, "1", null, "区县汇总");

        // 高校汇总数据
        total += fetchAndSaveTraining(token, baseUrl, endpoint, year, "2", null, "高校汇总");

        // 区县列表
        Result countyResult = oneFormService.countyList(year);
        if (countyResult == null || !Objects.equals(countyResult.getCode(), 200)) {
            return Result.error("获取区县列表失败：" + countyResult.getMessage());
        }

        JSONArray countyData = (JSONArray) countyResult.getData();
        if (countyData != null) {
            for (int i = 0; i < countyData.size(); i++) {
                JSONObject county = countyData.getJSONObject(i);
                String countyName = county.getString("countyName");
                if (StrUtil.isNotBlank(countyName)) {
                    total += fetchAndSaveTraining(token, baseUrl, endpoint, year, "1", countyName, countyName);
                }
            }
        }

        log.info("培训教师数据保存完成，共 {} 条", total);
        return Result.success("培训教师数据保存完成，共 " + total + " 条记录");
    }

    private int fetchAndSaveTraining(String token, String baseUrl, String endpoint,
                                     String year, String type, String nameParam, String name) {
        JSONObject form = new JSONObject();
        form.put("year", year);
        if (StrUtil.isNotBlank(type)) form.put("type", type);
        if (StrUtil.isNotBlank(nameParam)) form.put("name", nameParam);

        try {
            JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
            JSONObject data = result.getJSONObject("data");
            if (data != null && !data.isEmpty()) {
                Training training = new Training();
                training.setName(name);
                training.setTotal(data.getIntValue("total"));
                training.setNation(data.getIntValue("nation"));
                training.setProvince(data.getIntValue("province"));
                training.setPlace(data.getIntValue("place"));
                training.setCounty(data.getIntValue("county"));
                training.setSchool(data.getIntValue("school"));
                training.setKindergarten(data.getIntValue("kindergarten"));
                training.setSmallSchool(data.getIntValue("primary"));
                training.setJunior(data.getIntValue("junior"));
                training.setSenior(data.getIntValue("senior"));
                training.setSpecial(data.getIntValue("special"));
                training.setVocational(data.getIntValue("vocational"));
                training.setUniversity(data.getIntValue("university"));
                training.setColleges(data.getIntValue("colleges"));
                training.setAdult(data.getIntValue("adult"));

                ApiDbHelper.fillTimestamps(training);
                ApiDbHelper.insertOrUpdate(trainingMapper, training, (LambdaQueryWrapper<Training> wrapper) ->
                        wrapper.eq(Training::getName, training.getName())
                );
                return 1;
            }
        } catch (Exception e) {
            log.error("调用培训教师接口失败：[name={}, type={}]：{}", name, type, e.getMessage());
        }
        return 0;
    }

    @Override
    public Result saveTrainingDetail(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/trainingDetail";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        try {
            // ---------- type = 1，区县数据 ----------
            JSONObject form1 = new JSONObject();
            form1.put("year", year);
            form1.put("type", "1");

            JSONObject response1 = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form1);
            JSONArray data1 = response1.getJSONArray("data");

            if (data1 != null && !data1.isEmpty()) {
                for (int i = 0; i < data1.size(); i++) {
                    JSONObject item = data1.getJSONObject(i);
                    String name = item.getString("name");
                    Integer num = item.getIntValue("num");

                    TrainingDetail detail = new TrainingDetail();
                    detail.setName(name);
                    detail.setNum(num);
                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(trainingDetailMapper, detail,
                            (wrapper) -> wrapper.eq(TrainingDetail::getName, name));

                    total++;
                }
            }

            // ---------- type = 2，高校数据 ----------
            JSONObject form2 = new JSONObject();
            form2.put("year", year);
            form2.put("type", "2");

            JSONObject response2 = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form2);
            JSONArray data2 = response2.getJSONArray("data");

            if (data2 != null && !data2.isEmpty()) {
                for (int i = 0; i < data2.size(); i++) {
                    JSONObject item = data2.getJSONObject(i);
                    String name = item.getString("name");
                    Integer num = item.getIntValue("num");

                    TrainingDetail detail = new TrainingDetail();
                    detail.setName(name);
                    detail.setNum(num);
                    ApiDbHelper.fillTimestamps(detail);

                    ApiDbHelper.insertOrUpdate(trainingDetailMapper, detail,
                            (wrapper) -> wrapper.eq(TrainingDetail::getName, name));

                    total++;
                }
            }

        } catch (Exception e) {
            log.error("保存培训教师详情失败：{}", e.getMessage(), e);
            return Result.error("保存失败：" + e.getMessage());
        }

        return Result.success("保存成功，共 " + total + " 条培训教师详情记录");
    }

    @Override
    public Result saveSchoolDetail(String year) {

        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        List<JSONObject> allSchools = new ArrayList<>();

        // 普通学校列表
        Result schoolResult = oneFormService.schoolList(year, "", "", "", 1, 10000);
        if (schoolResult == null || schoolResult.getCode() != 200) {
            return Result.error("获取学校列表失败");
        }
        JSONObject schoolData = (JSONObject) schoolResult.getData();
        if (schoolData == null || !schoolData.containsKey("list")) {
            return Result.error("学校列表数据格式异常");
        }
        JSONArray schoolList = schoolData.getJSONArray("list");
        if (schoolList == null || schoolList.isEmpty()) {
            return Result.error("学校列表为空");
        }
        allSchools.addAll(schoolList.toJavaList(JSONObject.class));
        // 高校列表
        Result highListResult = oneFormService.highList(year);
        if (highListResult == null || highListResult.getCode() != 200) {
            return Result.error("获取高校列表失败");
        }
        Object highData = highListResult.getData();
        if (highData instanceof JSONArray) {
            JSONArray highSchoolList = (JSONArray) highData;
            if (highSchoolList != null && !highSchoolList.isEmpty()) {
                allSchools.addAll(highSchoolList.toJavaList(JSONObject.class));
            }
        } else {
            return Result.error("高校列表数据格式异常");
        }

        if (allSchools.isEmpty()) {
            return Result.error("学校列表为空");
        }

        String baseUrl = ybtConfig.getUrl();
        String endpoint = "/api/v1/data/schoolDetail";
        AtomicInteger total = new AtomicInteger(0);

        for (JSONObject school : allSchools) {
            String orgNo = school.getString("orgnazitionNo");
            String orgName = school.getString("orgnazitionName");

            try {
                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("orgnazitionNo", orgNo);

                JSONObject result = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);

                if (result == null || result.getIntValue("code") != 0) {
                    log.warn("接口请求失败，orgnazitionNo={}, message={}", orgNo, result == null ? "null" : result.getString("message"));
                    continue;
                }

                JSONObject dataWrapper = result.getJSONObject("data");
                if (dataWrapper == null) {
                    log.warn("接口返回缺失 data，orgnazitionNo={}", orgNo);
                    continue;
                }

                JSONObject dataObj = dataWrapper.getJSONObject("data");
                String type = dataWrapper.getString("type");
                if (dataObj == null) {
                    log.warn("接口返回缺失 data->data，orgnazitionNo={}", orgNo);
                    continue;
                }

                SchoolDetail detail = new SchoolDetail();
                detail.setName(orgName);
                detail.setType(type);
                detail.setCourses(dataObj.getInteger("courses"));
                detail.setCoursesGap(dataObj.getInteger("coursesGap"));
                detail.setPsychology(dataObj.getInteger("psychology"));
                detail.setPsychologyGap(dataObj.getInteger("psychologyGap"));
                detail.setSportsNum(dataObj.getInteger("sportsNum"));
                detail.setArtNum(dataObj.getInteger("artNum"));
                detail.setJzgNum(dataObj.getInteger("jzgNum"));
                detail.setZrjsNum(dataObj.getInteger("zrjsNum"));
                detail.setInduction(dataObj.getInteger("induction"));
                detail.setInductionPercent(dataObj.getString("inductionPercent"));
                detail.setMan(dataObj.getInteger("man"));
                detail.setWoman(dataObj.getInteger("woman"));
                detail.setGenderPercent(dataObj.getString("gender"));
                detail.setTproPercent(dataObj.getString("tproPercent"));

                //授课教师数

                // 职称
                JSONArray lesson = dataObj.getJSONArray("lesson");
                if (lesson != null) {
                    for (int j = 0; j < lesson.size(); j++) {
                        JSONObject t = lesson.getJSONObject(j);
                        String lessonName = t.getString("name").trim();
                        int num = t.getIntValue("num");
                        switch (lessonName) {
                            case "哲学":
                                detail.setLessonZhexue(num);
                                break;
                            case "经济学":
                                detail.setLessonJingjixue(num);
                                break;
                            case "法学":
                                detail.setLessonFaxue(num);
                                break;
                            case "教育学":
                                detail.setLessonJiaoyuxue(num);
                                break;
                            case "文学":
                                detail.setLessonWenxue(num);
                                break;
                            case "历史学":
                                detail.setLessonLishixue(num);
                                break;
                            case "理学":
                                detail.setLessonLixue(num);
                                break;
                            case "工学":
                                detail.setLessonGongxue(num);
                                break;
                            case "农学":
                                detail.setLessonNongxue(num);
                                break;
                            case "医学":
                                detail.setLessonYixue(num);
                                break;
                            case "管理学":
                                detail.setLessonGuanlixue(num);
                                break;
                        }
                    }
                }

                // 培训信息
                JSONObject training = dataObj.getJSONObject("training");
                if (training != null) {
                    detail.setTrainTotal(training.getInteger("total"));
                    detail.setTrainCounty(training.getInteger("county"));
                    detail.setTrainCity(training.getInteger("city"));
                    detail.setTrainNation(training.getInteger("nation"));
                    detail.setTrainCountyPercent(training.getString("countyPercent"));
                    detail.setTrainCityPercent(training.getString("cityPercent"));
                    detail.setTrainNationPercent(training.getString("nationPercent"));
                }

                // 职称
                JSONArray titles = dataObj.getJSONArray("title");
                if (titles != null) {
                    for (int j = 0; j < titles.size(); j++) {
                        JSONObject t = titles.getJSONObject(j);
                        String titleName = t.getString("name").trim();
                        int num = t.getIntValue("num");
                        switch (titleName) {
                            case "正高级":
                                detail.setTitleZg(num);
                                break;
                            case "副高级":
                                detail.setTitleFg(num);
                                break;
                            case "中级":
                                detail.setTitleZj(num);
                                break;
                            case "助理级":
                                detail.setTitleZlj(num);
                                break;
                            case "员级":
                                detail.setTitleYj(num);
                                break;
                            case "未定职级":
                                detail.setTitleNone(num);
                                break;
                        }
                    }
                }
                detail.setGradePercent(dataObj.getString("gradePercent"));

                // 学历
                JSONArray qualifications = dataObj.getJSONArray("qualification");
                if (qualifications != null) {
                    for (int j = 0; j < qualifications.size(); j++) {
                        JSONObject q = qualifications.getJSONObject(j);
                        String name = q.getString("name").trim();
                        int num = q.getIntValue("num");
                        switch (name) {
                            case "博士研究生":
                                detail.setEduBoshi(num);
                                break;
                            case "硕士研究生":
                                detail.setEduShuoshi(num);
                                break;
                            case "本科":
                                detail.setEduBenke(num);
                                break;
                            case "专科":
                                detail.setEduZhuanke(num);
                                break;
                            case "高中阶段":
                                detail.setEduGaozhong(num);
                                break;
                            case "高中阶段以下":
                                detail.setEduOthers(num);
                                break;
                        }
                    }
                }
                detail.setBenkePercent(dataObj.getString("benke"));
                detail.setYjsPercent(dataObj.getString("yjs"));

                // 年龄结构
                JSONArray ages = dataObj.getJSONArray("age");
                if (ages != null) {
                    for (int j = 0; j < ages.size(); j++) {
                        JSONObject age = ages.getJSONObject(j);
                        String ageTitle = age.getString("title").trim();
                        int num = age.getIntValue("num");
                        switch (ageTitle) {
                            case "≤34岁":
                                detail.setAge_34_down(num);
                                break;
                            case "35-39岁":
                                detail.setAge_35_39(num);
                                break;
                            case "40-44岁":
                                detail.setAge_40_44(num);
                                break;
                            case "45-49岁":
                                detail.setAge_45_49(num);
                                break;
                            case "50-54岁":
                                detail.setAge_50_54(num);
                                break;
                            case "55-59岁":
                                detail.setAge_55_59(num);
                                break;
                            case "≥60岁":
                                detail.setAge_60_up(num);
                                break;
                        }
                    }
                }

                ApiDbHelper.fillTimestamps(detail);
                ApiDbHelper.insertOrUpdate(schoolDetailMapper, detail, wrapper ->
                        wrapper.eq(SchoolDetail::getName, detail.getName())
                );

                total.incrementAndGet();

            } catch (Exception e) {
                log.error("保存学校详情失败，orgnazitionNo={}，错误信息：{}", orgNo, e.getMessage(), e);
            }
        }

        log.info("学校详情数据保存完成，共 {} 条", total.get());
        return Result.success("学校详情数据保存完成，共 " + total.get() + " 条记录");
    }

    @Override
    public Result saveKpi(String year) {
        if (StrUtil.isBlank(year)) {
            return Result.error("year 参数不能为空");
        }

        String token = TokenManager();
        if (StrUtil.isBlank(token)) {
            return Result.error("获取 token 失败");
        }

        String endpoint = "/api/v1/data/kpi";
        String baseUrl = ybtConfig.getUrl();
        int total = 0;

        try {
            // ---------- 汇总数据 ----------
            JSONObject formAll = new JSONObject();
            formAll.put("year", year);
            formAll.put("type", 1);

            JSONObject allResponse = ApiDbHelper.postAndParse(token, baseUrl, endpoint, formAll);
            if (allResponse != null) {
                JSONObject allData = allResponse.getJSONObject("data");
                if (allData != null) {
                    DistrictKpi all = new DistrictKpi();
                    all.setDistrict("汇总");
                    all.setGradePercent(parsePercent(allData.getString("gradePercent")));
                    all.setYjsPercent(parsePercent(allData.getString("yjsPercent")));
                    all.setBenKePercent(parsePercent(allData.getString("benKePercent")));
                    all.setMGraduatePercent(parsePercent(allData.getString("mGraduatePercent")));
                    all.setPUndergraduatePercent(parsePercent(allData.getString("pUndergraduatePercent")));
                    all.setSchoolSizePercent(parsePercent(allData.getString("schoolSizePercent")));
                    all.setClassSizePercent(parsePercent(allData.getString("classSizePercent")));

                    ApiDbHelper.fillTimestamps(all);

                    ApiDbHelper.insertOrUpdate(districtKpiMapper, all,
                            wrapper -> wrapper.eq(DistrictKpi::getDistrict, "汇总"));

                    total++;
                }
            }

            // ---------- 各区县数据 ----------
            Result countyResult = oneFormService.countyList(year);
            if (countyResult == null || countyResult.getData() == null) {
                return Result.error("获取区县列表失败");
            }

            List<JSONObject> countyDataList = (List<JSONObject>) countyResult.getData();

            for (JSONObject json : countyDataList) {
                String county = json.getString("countyName");
                if ("汇总".equals(county)) continue;

                JSONObject form = new JSONObject();
                form.put("year", year);
                form.put("type", 1);
                form.put("name", county);

                JSONObject response = ApiDbHelper.postAndParse(token, baseUrl, endpoint, form);
                if (response == null) continue;

                JSONObject data = response.getJSONObject("data");
                if (data == null) continue;

                DistrictKpi kpi = new DistrictKpi();
                kpi.setDistrict(county);
                kpi.setGradePercent(parsePercent(data.getString("gradePercent")));
                kpi.setYjsPercent(parsePercent(data.getString("yjsPercent")));
                kpi.setBenKePercent(parsePercent(data.getString("benKePercent")));
                kpi.setMGraduatePercent(parsePercent(data.getString("mGraduatePercent")));
                kpi.setPUndergraduatePercent(parsePercent(data.getString("pUndergraduatePercent")));
                kpi.setSchoolSizePercent(parsePercent(data.getString("schoolSizePercent")));
                kpi.setClassSizePercent(parsePercent(data.getString("classSizePercent")));

                ApiDbHelper.fillTimestamps(kpi);

                ApiDbHelper.insertOrUpdate(districtKpiMapper, kpi,
                        wrapper -> wrapper.eq(DistrictKpi::getDistrict, county));

                total++;
            }

        } catch (Exception e) {
            log.error("保存绩效指标失败：{}", e.getMessage(), e);
            return Result.error("保存失败：" + e.getMessage());
        }

        return Result.success("保存成功，共 " + total + " 条绩效指标记录（含汇总）");
    }

    private BigDecimal parsePercent(String percentStr) {
        if (percentStr == null || percentStr.isEmpty()) return BigDecimal.ZERO;
        try {
            return new BigDecimal(percentStr.replace("%", "").trim());
        } catch (Exception e) {
            log.warn("解析百分比失败，原始字符串：{}", percentStr);
            return BigDecimal.ZERO;
        }
    }
}

